/*
* // +-------------------------------------------------------------------------------------------------
* // |                 有你就好 [ 有节骨乃坚，无心品自端 ]     <http://encoding.wang>
* // +-------------------------------------------------------------------------------------------------
* // |                             独在异乡为异客         每逢佳节倍思亲
* // +-------------------------------------------------------------------------------------------------
* // |                 联系:   <707069100@qq.com>      <http://weibo.com/513778937>
* // +-------------------------------------------------------------------------------------------------
*/

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                   ErYang出品 属于小极品          共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------


package wang.encoding.mroot.admin.controller.system.generate


import com.baomidou.mybatisplus.plugins.Page
import org.apache.shiro.authz.annotation.RequiresPermissions
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.servlet.ModelAndView
import org.springframework.web.servlet.mvc.support.RedirectAttributes
import wang.encoding.mroot.admin.common.controller.BaseAdminController
import wang.encoding.mroot.admin.common.controller.GenerateModel
import wang.encoding.mroot.common.annotation.RequestLogAnnotation
import wang.encoding.mroot.common.business.ResultData
import wang.encoding.mroot.common.constant.RequestLogConstant
import wang.encoding.mroot.common.exception.ControllerException
import wang.encoding.mroot.common.util.FileUtil
import wang.encoding.mroot.common.util.FreemarkerUtil
import wang.encoding.mroot.common.util.PathUtil
import wang.encoding.mroot.common.util.StringUtil
import wang.encoding.mroot.service.system.ConfigService
import java.math.BigInteger
import java.util.*
import javax.servlet.http.HttpServletRequest


/**
 * 代码生成控制器
 *
 * @author ErYang
 */
@RestController
@RequestMapping(value = ["/generateCode"])
class GenerateCodeController : BaseAdminController() {


    @Autowired
    private lateinit var configService: ConfigService


    companion object {

        /**
         * 模块
         */
        private const val MODULE_NAME: String = "/generateCode"
        /**
         * 首页
         */
        /**
         * 视图目录
         */
        private const val VIEW_PATH: String = "/system/generateCode"

        private const val INDEX: String = "/index"
        private const val INDEX_URL: String = MODULE_NAME + INDEX
        private const val INDEX_VIEW: String = VIEW_PATH + INDEX
        /**
         * 生成
         */
        private const val GENERATE: String = "/generate"
        private const val GENERATE_URL: String = MODULE_NAME + GENERATE
        private const val GENERATE_VIEW: String = VIEW_PATH + GENERATE

        private const val SAVE: String = "/save"
        private const val SAVE_URL: String = MODULE_NAME + SAVE

    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 列表页面
     *
     * @param request HttpServletRequest
     * @return ModelAndView
     */
    @RequiresPermissions(value = [(GenerateCodeController.INDEX_URL)])
    @RequestMapping(INDEX)
    @RequestLogAnnotation(module = RequestLogConstant.ADMIN_MODULE,
            title = RequestLogConstant.ADMIN_MODULE_GENERATE_VIEW)
    @Throws(ControllerException::class)
    fun index(request: HttpServletRequest): ModelAndView {
        val modelAndView = ModelAndView(super.initView(INDEX_VIEW))
        super.initViewTitleAndModelUrl(INDEX_URL, MODULE_NAME, request)

        val table: String? = request.getParameter("table")
        var tableArray: ArrayList<String>? = null
        if (null != table && table.isNotBlank()) {
            tableArray = arrayListOf()
            tableArray.add(table.trim())
            modelAndView.addObject("table", table.trim())
        }
        val page: Page<Map<String, String>> = configService.listTable2PageByMap(initPage(request),
                tableArray)!!
        modelAndView.addObject("page", page)
        return modelAndView
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 生成页面
     *
     * @param table String
     * @param request HttpServletRequest
     * @param redirectAttributes RedirectAttributes
     * @return ModelAndView
     */
    @RequiresPermissions(value = [GENERATE_URL])
    @RequestMapping(value = ["$GENERATE/{table}"])
    @RequestLogAnnotation(module = RequestLogConstant.ADMIN_MODULE,
            title = RequestLogConstant.ADMIN_MODULE_GENERATE_CODE_VIEW)
    @Throws(ControllerException::class)
    fun generate(@PathVariable("table") table: String,
                 request: HttpServletRequest, redirectAttributes: RedirectAttributes): ModelAndView {
        val modelAndView = ModelAndView(super.initView(GENERATE_VIEW))
        super.initViewTitleAndModelUrl(GENERATE_URL, MODULE_NAME, request)

        // 环境
        if (super.devProfile()) {
            if (table.isBlank()) {
                super.addFailMessage(redirectAttributes,
                        localeMessageSourceConfiguration.getMessage("message.info.error"))
                modelAndView.viewName = super.initRedirectUrl(INDEX_URL)
                return modelAndView
            }
            modelAndView.addObject("table", table)
        } else {
            super.addFailMessage(redirectAttributes,
                    localeMessageSourceConfiguration.getMessage("message.generateCode.error"))
            modelAndView.viewName = super.initRedirectUrl(INDEX_URL)
            return modelAndView
        }

        // 设置上个请求地址
        super.initRefererUrl(request)
        return modelAndView
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 处理生成
     *
     * @param request HttpServletRequest
     * @param redirectAttributes RedirectAttributes
     * @return ModelAndView
     */
    @RequiresPermissions(value = [(GenerateCodeController.SAVE_URL)])
    @RequestMapping(SAVE)
    @RequestLogAnnotation(module = RequestLogConstant.ADMIN_MODULE,
            title = RequestLogConstant.ADMIN_MODULE_GENERATE_SAVE)
    @Throws(ControllerException::class)
    fun save(request: HttpServletRequest, redirectAttributes: RedirectAttributes): Any {
        if (httpRequestUtil.isAjaxRequest(request)) {
            val failResult: ResultData = ResultData.fail()
            // 环境
            if (!super.devProfile()) {
                return super.initErrorJSONObject(failResult, "message.generateCode.error")
            }

            val table: String? = request.getParameter("table")
            if (null == table || table.isBlank()) {
                return super.initErrorCheckJSONObject(failResult)
            }


            // 是否保留前缀
            var tablePrefix: String? = request.getParameter("tablePrefix")

//        // 要查询的表
//        val tableArray: Array<String?> = arrayOfNulls(2)
//        tableArray[0] = table
//        val param = HashMap<String, Any>()
//        param["tableArray"] = tableArray
//        // 查询表
//        val tableList: List<Map<String, String>>? = configService.listTableByMap(param)
            val tableList: List<Map<String, String>>? = configService.getTableByTableName(table)
            if (null == tableList || tableList.isEmpty()) {
                return super.initErrorCheckJSONObject(failResult)
            }
            // 生成
            if (null == tablePrefix) {
                tablePrefix = ""
            }
            // 生成
            init(tablePrefix, tableList)
            return super.initGenerateJSONObject(BigInteger.ONE)
        } else {
            return super.initErrorRedirectUrl()
        }
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 生成
     *
     * @param tablePrefixName String 是否保留表前缀
     * @param tableList List<Map<String, String>>  表列表
     */
    private fun init(tablePrefixName: String, tableList: List<Map<String, String>>) {
        // 生成代码前,先清空之前生成的代码
        FileUtil.delFolder(PathUtil.classpath + "generate")
        // 表名
        var tableName: String
        // 实体类名描述
        var classComment: String
        // 表描述
        var tableComment: String
        // 类名
        var className: String
        // 表前缀
        var tablePrefix: String
        // 类前缀
        var classPrefix: String
        // 属性集合
        val fieldList = ArrayList<Array<String>>()
        // 生成内容 model
        val generateModels = ArrayList<Any>()
        var i = 0
        // 表详情
        var tableDetailList: List<Map<String, String>>
        // 备注
        var defaultVal: String
        // 数据库中的数据类型
        var dataType: String
        // 数据库中的数据类型 大写
        var dataTypeUpperCase: String
        // 字段
        var filed: String
        // 创建数据模型
        val root = HashMap<String, Any>()
        // 数据库id
        val dataId = "id"
        // 数据库id 类型
        var dataIdType: String? = null
        //  数据库id 类型 大写
        var dataIdTypeUpperCase: String? = null
        val tableVar = "表"
        val lineVar = "_"
        val splitName = "#"
        for (tableMap: Map<String, String> in tableList) {
            // 表名
            tableName = tableMap["tableName"] as String
            // 表描述
            tableComment = tableMap["tableComment"] as String
            // 表前缀
            tablePrefix = if (tableName.contains(lineVar)) {
                tableName.substring(0, tableName.indexOf(lineVar))
            } else {
                ""
            }
            // 实体类描述
            // 移除带表名的字
            classComment = if (tableComment.endsWith(tableVar)) {
                tableComment.substring(0, tableComment.lastIndexOf(tableVar))
            } else {
                tableComment
            }
            // 保留前缀
            className = if (configProperties.bootstrapSwitchEnabled == tablePrefixName) {
                StringUtil.lineToHump(tableName)
            } else {
                if (tablePrefix.isNotBlank()) {
                    StringUtil.lineToHump(tableName.substring(tablePrefix.length + 1))
                } else {
                    StringUtil.lineToHump(tableName)
                }
            }
            // 类名首字母大写
            className = StringUtil.firstUpperCase(className)!!
            // 类前缀 首字母小写
            classPrefix = StringUtil.lineToHump(tablePrefix)
            // 表详情
            tableDetailList = configService.getTableDetailTableName(tableName)!!
            for (map: Map<String, String> in tableDetailList) {
                // 表备注
                defaultVal = if (null == map["columnComment"]) " " else map["columnComment"] as String
                // 数据库中的数据类型
                dataType = map["dataType"] as String
                // 数据库中的数据类型 大写
                dataTypeUpperCase = initDataTypeUpperCase(dataType)
                // 数据库数据类型转为 mybatis 类型
                dataType = initDataType(dataType)
                // 表id
                if (dataId == map["columnName"]) {
                    dataIdType = dataType
                    dataIdTypeUpperCase = dataTypeUpperCase
                }

                // 字段
                filed = (map["columnName"].toString() + splitName + dataType + splitName
                        + dataTypeUpperCase + splitName + defaultVal + splitName
                        + StringUtil.lineToHump(map["columnName"] as String))

                // 属性放到集合里面
                fieldList.add(filed.split(splitName.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray())
                // 初始化 GenerateModel
                val generateModel: GenerateModel = initGenerateModel(dataId, fieldList[i])
                generateModels.add(generateModel)
                i++
            }
            // 初始化节点数据
            initRoot(className, classPrefix, tableName, tablePrefix, tableComment, classComment, dataId,
                    dataIdType,
                    dataIdTypeUpperCase
                    , generateModels, fieldList, root)
            // 初始化 freemarker 数据
            initFreemarker(className, root)
        }
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 数据库字段类型转为大写
     *
     *  @param dataType String
     * @return String
     */
    private fun initDataTypeUpperCase(dataType: String): String {
        return if ("int".equals(dataType, ignoreCase = true) || "integer".equals(dataType, ignoreCase = true)) {
            "INTEGER"
        } else if ("tinyint".equals(dataType, ignoreCase = true)) {
            "TINYINT"
        } else if ("bigint".equals(dataType, ignoreCase = true)) {
            "BIGINT"
        } else if ("text".equals(dataType, ignoreCase = true)) {
            "VARCHAR"
        } else if ("datetime".equals(dataType, ignoreCase = true) || "timestamp".equals(dataType, ignoreCase = true)) {
            "TIMESTAMP"
        } else {
            dataType.toUpperCase()
        }

    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 数据库字段类型转为 Java 类型
     *
     *  @param dataType String
     * @return String
     */
    private fun initDataType(dataType: String): String {
        val dataTypeUpperCase: String
        if ("int".equals(dataType, ignoreCase = true) || "integer".equals(dataType, ignoreCase = true)) {
            dataTypeUpperCase = "Long"
        } else if ("tinyint".equals(dataType, ignoreCase = true)) {
            dataTypeUpperCase = "Int"
        } else if ("bigint".equals(dataType, ignoreCase = true)) {
            dataTypeUpperCase = "BigInteger"
        } else if ("datetime".equals(dataType, ignoreCase = true) || "timestamp".equals(dataType, ignoreCase = true)) {
            dataTypeUpperCase = "Date"
        } else if ("date".equals(dataType, ignoreCase = true)) {
            dataTypeUpperCase = "Date"
        } else if ("decimal".equals(dataType, ignoreCase = true)) {
            dataTypeUpperCase = "BigDecimal"
        } else if ("text".equals(dataType, ignoreCase = true) || "varchar".equals(dataType, ignoreCase = true)) {
            dataTypeUpperCase = "String"
        } else {
            dataTypeUpperCase = "String"
        }
        return dataTypeUpperCase
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 初始化 GenerateModel
     *
     *  @param dataId String 表ID
     *  @param fieldList Array<String> 字段集合
     * @return GenerateModel
     */
    private fun initGenerateModel(dataId: String,
                                  fieldList: Array<String>): GenerateModel {
        // 移除类前缀驼峰命名
        val removeClassPrefixHump: String = StringUtil.lineToHump(fieldList[0])
        // 移除类前缀驼峰命名 首字母小写
        val removeClassPrefixFirstLowerCaseHump: String? = StringUtil.firstUpperCase(removeClassPrefixHump)
        // GenerateModel
        val generateModel = GenerateModel()
        generateModel.name = fieldList[0]
        generateModel.type = fieldList[1]
        generateModel.dataType = fieldList[2]
        generateModel.comment = fieldList[3]
        generateModel.defaultValue = fieldList[4]
        generateModel.dataId = dataId
        generateModel.camelCaseName = removeClassPrefixHump
        generateModel.firstCapitalizeCamelCaseName = removeClassPrefixFirstLowerCaseHump
        generateModel.finalName = fieldList[0].toUpperCase()
        return generateModel
    }

    // -------------------------------------------------------------------------------------------------

    /**
     * 初始化节点数据
     *
     *  @param className String 类名称
     *  @param classPrefix String 类前缀
     *  @param tableName String 表名称
     *  @param tablePrefix String 表前缀
     *  @param tableComment String 表描述
     *  @param classComment String 类描述
     *  @param dataId String 表ID
     *  @param dataIdType String 表id类型
     *  @param dataIdTypeUpperCase String 表id类型大写
     *  @param generateModels ArrayList<Any> 模型集合
     *  @param fieldList ArrayList<Array<String>> 字段集合
     *  @param root HashMap<String, Any> 节点集合
     *
     * @return HashMap<String, Any>
     */
    private fun initRoot(className: String, classPrefix: String,
                         tableName: String, tablePrefix: String, tableComment: String, classComment: String,
                         dataId: String, dataIdType: String?, dataIdTypeUpperCase: String?,
                         generateModels: ArrayList<Any>, fieldList: ArrayList<Array<String>>,
                         root: HashMap<String, Any>): HashMap<String, Any> {
        // Model层包名
        val modelPackageName = "wang.encoding.mroot.model.entity"
        // Controller层包名
        val controllerPackageName = "wang.encoding.mroot.admin.controller"
        // Service层包名
        val servicePackageName = "wang.encoding.mroot.service"
        // Mapper层包名
        val mapperPackageName = "wang.encoding.mroot.mapper"

        // 创建数据模型
        root["fieldList"] = fieldList
        root["generateModels"] = generateModels
        // 类名
        root["className"] = className
        // 类名大写
        root["classNameUppercase"] = className.toUpperCase()
        // 类名首字母小写
        root["classFirstLowerCaseName"] = className.substring(0, 1).toLowerCase() + className.substring(1)
        // 当前日期
        root["nowDate"] = Date()
        // 类前缀
        root["classPrefix"] = classPrefix
        // 类前缀大写
        root["classPrefixUppercase"] = classPrefix.toUpperCase()
        // 表名称
        root["tableName"] = tableName
        // 表前缀
        root["tablePrefix"] = tablePrefix
        // 表描述
        root["tableComment"] = tableComment
        // model描述
        root["classComment"] = classComment
        // 表id
        root["dataId"] = dataId
        if (null == dataIdType) {
            root["dataIdType"] = "BigInteger"
        } else {
            root["dataIdType"] = dataIdType
        }

        if (null == dataIdTypeUpperCase) {
            root["dataIdTypeUpperCase"] = "BIGINT"
        } else {
            root["dataIdTypeUpperCase"] = dataIdTypeUpperCase
        }
        root["modelPackageName"] = modelPackageName
        root["mapperPackageName"] = mapperPackageName
        root["servicePackageName"] = servicePackageName
        root["controllerPackageName"] = controllerPackageName
        return root
    }

    // -------------------------------------------------------------------------------------------------

    /**
     *  初始化 freemarker 数据
     *
     *  @param className String 类名称
     *  @param root HashMap<String, Any> 节点数据
     *
     *  @return HashMap<String, Any>
     */
    private fun initFreemarker(className: String, root: HashMap<String, Any>) {
        // 存放路径
        val filePath = "generate/create/"
        // 模板路径
        val ftlPath = "/templates/view/default/generateCode/template"
        /* 生成 model */
        FreemarkerUtil.printFile("modelTemplate.ftl", root,
                "model/$className.kt", filePath,
                ftlPath)

        /* 生成 mapper */
        FreemarkerUtil.printFile("mapperTemplate.ftl", root,
                "mapper/" + className + "Mapper.kt",
                filePath, ftlPath)
        /* 生成 mybatis xml */
        FreemarkerUtil.printFile("mapperMybatisTemplate.ftl", root,
                "mybatis/" + className + "Mapper.xml",
                filePath, ftlPath)

        /* 生成 service */
        FreemarkerUtil.printFile("serviceTemplate.ftl", root,
                "service/" + StringUtil.firstLowerCase(className) + "/" + className + "Service.kt",
                filePath, ftlPath)
        /* 生成 serviceImpl */
        FreemarkerUtil.printFile("serviceImplTemplate.ftl", root,
                "service/" + StringUtil.firstLowerCase(className) + "/" + className + "ServiceImpl.kt",
                filePath, ftlPath)

        /* 生成 controller */
        FreemarkerUtil.printFile("controllerTemplate.ftl", root,
                "controller/" + StringUtil.firstLowerCase(className) + "/" + className + "Controller.kt",
                filePath, ftlPath)


        /* 国际化信息 */
        FreemarkerUtil.printFile("zh_CNTemplate.ftl", root,
                "il8n/" + StringUtil.firstLowerCase(className) + "_zh_CN.properties",
                filePath, ftlPath)
        FreemarkerUtil.printFile("en_USTemplate.ftl", root,
                "il8n/" + StringUtil.firstLowerCase(className) + "_en_US.properties",
                filePath, ftlPath)


        /* 生成 Freemarker 页面 */
        FreemarkerUtil.printFile("ftlIndexTemplate.ftl", root,
                "ftl/" + StringUtil.firstLowerCase(className) + "/index.ftl",
                filePath, ftlPath)
        FreemarkerUtil.printFile("ftlAddTemplate.ftl", root,
                "ftl/" + StringUtil.firstLowerCase(className) + "/add.ftl",
                filePath, ftlPath)
        FreemarkerUtil.printFile("ftlEditTemplate.ftl", root,
                "ftl/" + StringUtil.firstLowerCase(className) + "/edit.ftl",
                filePath, ftlPath)
        FreemarkerUtil.printFile("ftlViewTemplate.ftl", root,
                "ftl/" + StringUtil.firstLowerCase(className) + "/view.ftl",
                filePath, ftlPath)

        FreemarkerUtil.printFile("ftlRecycleBinTemplate.ftl", root,
                "ftl/" + StringUtil.firstLowerCase(className) + "/recycleBin.ftl",
                filePath, ftlPath)

        /* 生成 js 页面 */
        FreemarkerUtil.printFile("jsTemplate.ftl", root,
                "ftl/" + StringUtil.firstLowerCase(className) + "/" + StringUtil.firstLowerCase(className) + "Js.ftl",
                filePath, ftlPath)

        /* 生成 ftl readme.md */
        FreemarkerUtil.printFile("readmeFtlTemplate.ftl", root,
                "ftl/" + StringUtil.firstLowerCase(className) + "/README.md",
                filePath, ftlPath)
    }

    // -------------------------------------------------------------------------------------------------

}

// -----------------------------------------------------------------------------------------------------

// End GenerateCodeController class

/* End of file GenerateCodeController.kt */
/* Location: ./src/main/kotlin/wang/encoding/mroot/admin/controller/system/generate/GenerateCodeController.kt */

// -----------------------------------------------------------------------------------------------------
// +----------------------------------------------------------------------------------------------------
// |                           ErYang出品 属于小极品  O(∩_∩)O~~   共同学习    共同进步
// +----------------------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------
